(function () {

    window.ss = window.ss || {};

    var _toString = Object.prototype.toString;

    /**
     * each方法的回调函数
     * @callback eachArrayCallback
     * @param {*} item 数组元素
     * @param {Number} index 数组元素索引
     * @param {Array} array 遍历的数组
     */

    /**
     * each方法的回调函数
     * @callback eachObjectCallback
     * @param {String} propName 属性名称
     * @param {*} propValue 属性值
     * @param {Object} object 遍历的对象
     */

    /**
     * 迭代处理数组中的每个元素
     * @method each
     * @param {Array|Object} array 如果不是数组的话
     * @param {eachArrayCallback|eachObjectCallback} callback 回调函数
     */
    ss.each = function (array, callback) {
        if (ss.isUndefinedOrNull(array)) {
            return;
        }

        if (this.isArray(array)) {
            if (array && array.length > 0) {
                for (var i = 0, len = array.length; i < len; i++) {
                    if (callback(array[i], i, array) === false) {
                        return;
                    }
                }
            }
        } else {
            for (var p in array) {
                if (array.hasOwnProperty(p)) {
                    callback(p, array[p], array);
                }
            }
        }
    };

    /**
     * <p>判断值是否为空</p>
     * <p>下面的值，将判断为空<div><ul>
     * <li>null</li>
     * <li>undefined</li>
     * <li>空的数组</li>
     * <li>长度为0的字符串</li>
     * </ul></div>
     * @method isEmpty
     * @param {String|Array} v
     * @return {Boolean}
     */
    ss.isEmpty = function (v) {
        return v === null || v === undefined || ((ss.isArray(v) && !v.length)) || v === '';
    };

    /**
     * 判断值是否不为空，与isEmpty方法的值相反
     * @method isNotEmpty
     * @param {String|Array} v
     * @return {Boolean}
     */
    ss.isNotEmpty = function (v) {
        return !this.isEmpty.apply(this, arguments);
    };

    /**
     * 如果传递的参数为数组，则返回true，否则返回false。
     * @method isArray
     * @param {*} v
     * @return {Boolean}
     */
    ss.isArray = function (v) {
        return _toString.apply(v) === '[object Array]';
    };

    /**
     * 如果传递的参数为日期对象，则返回true，否则返回false。
     * @method isDate
     * @param {*} v
     * @return {Boolean}
     */
    ss.isDate = function (v) {
        return _toString.apply(v) === '[object Date]';
    };

    /**
     * 如果传递的参数为字符串，则返回true，否则返回false。
     * @method isString
     * @param {*} v
     * @return {Boolean}
     */
    ss.isString = function (v) {
        return typeof v === 'string';
    };

    /**
     * 如果传递的参数为布尔值，则返回true，否则返回false。
     * @method isBoolean
     * @param {*} v
     * @return {Boolean}
     */
    ss.isBoolean = function (v) {
        return typeof v === 'boolean';
    };

    /**
     * 如果传递的参数为数字,则返回true，否则返回false。
     * @param {*} v 判断该值是否是数字,并且不是无穷数
     * @return {Boolean}
     */
    ss.isNumber = function (v) {
        return typeof v === 'number';
    };

    /**
     * 如果传递的参数为函数对象，则返回true，否则返回false。
     * @method isFunction
     * @param {*} v
     * @return {Boolean}
     */
    ss.isFunction = function (v) {
        return _toString.apply(v) === '[object Function]';
    };

    /**
     * 判断一个变量有定义且不为null
     * @method  isDefinedAndNotNull
     * @param {*} o
     * @return {Boolean}
     */
    ss.isDefinedAndNotNull = function (o) {
        return !this.isUndefinedOrNull(o);
    };

    /**
     * 判断一个变量没定义或者为null
     * @method isUndefinedOrNull
     * @param {*} o
     * @return {Boolean}
     */
    ss.isUndefinedOrNull = function (o) {
        return this.isUndefined(o) || o == null;
    };

    /**
     * 判断一个变量是否没定义
     * @method  isUndefined
     * @param {*} o
     * @return {Boolean}
     */
    ss.isUndefined = function (o) {
        return !this.isDefined(o);
    };

    /**
     * 如果传递的参数为undefined，则返回true，否则返回false。
     * @method isDefined
     * @param {*} v
     * @return {Boolean}
     */
    ss.isDefined = function (v) {
        return typeof v !== 'undefined';
    };

    /**
     * 拷贝属性的值(不拷贝从原型继承的属性)
     * @param src
     * @param dest
     */
    ss.copyTo = function (src, dest) {
        this.each(src, function (p, v) {
            dest[p] = v;
        });
        return dest;
    };

    ss.deepCopy = function (obj) {
        if (ss.isUndefined(obj)) {
            return undefined;
        }

        if (obj === null) {
            return null;
        }

        return JSON.parse(JSON.stringify(obj));
    };

    /**
     * 产生一个递增的id
     * @method nextId
     * @return {Number}
     */
    ss.nextId = (function () {
        var c = 0;
        return function () {
            return ++c;
        };
    })();

    /**
     * 合并URL和参数
     * @param url
     * @param param
     */
    ss.combineUrlParam = function (url, param) {
        if (url.indexOf('?') == -1) {
            return url + "?" + param;
        } else {
            return url + "&" + param;
        }
    };

    ss.PageSize = 10;

})();


(function () {

    // 采用引用计数的方式
    ss._globalWaiting = null;
    ss._globalWaitingCount = 0;

    ss.showGlobalWaiting = function () {
        if (ss.isDefinedAndNotNull(ss._globalWaiting)) {
            ss._globalWaitingCount++;
            return;
        }

        ss._globalWaiting = layer.load();
        ss._globalWaitingCount = 1;
        return ss._globalWaiting;
    };

    ss.hideGlobalWaiting = function () {
        if (ss._globalWaitingCount <= 0) {
            return;
        }

        ss._globalWaitingCount--;

        if (ss._globalWaitingCount == 0) {
            layer.close(ss._globalWaiting);

            ss._globalWaiting = null;
        }
    };

})();

(function(){

    ss.text_highlight = function (text) {
        return '<span class="text-highlight">' + text + '</span>';
    };

    ss.confirm = function (content, yes) {
        var d = layer.confirm(content, {
            title: "",
            icon: 3
        }, function () {
            layer.close(d);
            yes();
        });
    };

})();

(function () {

    var defaultErrorHandler = function (data) {
        console.log(data.status, data.responseText);
        if (data.status == 500) {
            try {
                var jsondata = JSON.parse(data.responseText);
                if (jsondata.message) {
                    ss.showError(jsondata.message);
                }
            } catch (e) {
                ss.showError("出错了");
            }
        }
    };

    ss.ajaxPut = function (url, data) {
        console.log("put ", url, data);
        return $.ajax({
            url: url,
            type: 'put',
            contentType: "application/json",
            data: JSON.stringify(data),
            error: defaultErrorHandler
        });
    };

    ss.ajaxPost = function (url, data) {
        console.log("post ", url, data);
        return $.ajax({
            url: url,
            type: 'post',
            contentType: "application/json",
            data: JSON.stringify(data),
            error: defaultErrorHandler
        });
    };

    ss.ajaxQueryPaging = function (url, data) {
        return ss.ajaxGet(url, data);
    };

    ss.ajaxGet = function (url, data) {
        console.log("get ", url, data);

        return $.ajax({
            url: url,
            data: data,
            dataType: 'json',
            error: defaultErrorHandler
        });
    };

    ss.ajaxGetText = function (url, data) {
        console.log("get ", url, data);

        return $.ajax({
            url: url,
            data: data,
            error: defaultErrorHandler
        });
    };

    ss.ajaxDelete = function (url) {
        return $.ajax({
            url: url,
            type: 'delete',
            error: defaultErrorHandler
        });
    };

    ss.ajaxUploadForm = function ($form, callback) {
        var url = $form.attr("action");
        console.log("ajaxupload, ", url);

        return $.ajax({
            url: url,
            type: 'post',
            processData: false,
            contentType: false,
            async: true,
            data: new FormData($form[0]),
            error: defaultErrorHandler
        });
    };


    ss.extendCRUDAPI = function (api) {

        if (!api.urlPrefix) {
            new Error("api没有设置urlPrefix")
        }

        api.queryPaging = function (searchCondition) {
            return ss.ajaxQueryPaging(this.urlPrefix, searchCondition);
        };

        api.selectable = function () {
            return ss.ajaxGet(this.urlPrefix + "/selectable");
        };

        api.create = function (data) {
            return ss.ajaxPost(this.urlPrefix, data);
        };

        api.get = function (id) {
            return ss.ajaxGet(this.urlPrefix + "/" + id);
        };

        api.update = function (id, data) {
            console.log("update, id=" + id + ",data=", data);
            return ss.ajaxPut(this.urlPrefix + "/" + id, data);
        };

        api.delete0 = function (id) {
            return ss.ajaxDelete(this.urlPrefix + "/" + id);
        };

        api.action = function (id, actionName) {
            return ss.ajaxPost(this.urlPrefix + "/" + id + "/action/" + actionName);
        };

        return api;

    };

})();

/**
 * 数组操作工具类
 */
(function () {

    ss.array = ss.array || {};

    /**
     * 根据属性过滤
     * @method filterByProperty
     * @param {Array} array
     * @param {String} propertyName
     * @return {Array}
     */
    ss.array.filterByProperty = function (array, propertyName, propertyValue) {
        var ret = [];
        if (array) {
            for (var i = 0; i < array.length; i++) {
                var v = array[i][propertyName];
                if (v == propertyValue) {
                    ret.push(array[i]);
                }
            }
        }
        return ret;
    };

    /**
     * 根据属性过滤,查找第一条数据
     * @method filterByProperty
     * @param {Array} array
     * @param {String} propertyName
     * @return {Array}
     */
    ss.array.findFirstByProperty = function (array, propertyName, propertyValue) {
        var ret = [];
        if (array) {
            for (var i = 0; i < array.length; i++) {
                var v = array[i][propertyName];
                if (v == propertyValue) {
                    ret.push(array[i]);
                }
            }
        }

        return ret.length > 0 ? ret[0] : null;
    };

    /**
     * 迭代处理数组中的每个元素
     * @method each
     * @param {Array} array 如果不是数组的话
     * @param {eachArrayCallback} callback 回调函数
     */
    ss.array.each = function (array, callback) {
        if (array && array.length > 0) {
            for (var i = 0, len = array.length; i < len; i++) {
                if (callback(array[i], i, array) === false) {
                    return;
                }
            }
        }
    };

    /**
     * 将一个数组融合到目标数组中
     * 说明: 不使用concat方法，concat方法不会修改原数组。
     * @method  addAll
     * @param {Array} target 目标数组
     * @param {Array} array 数组
     * @return {Array}
     */
    ss.array.addAll = function (target, array, index) {
        ss.array.each(array, function (item) {
            ss.array.add(target, item, index);
        });
    };

    /**
     * 移除数组中某几项
     * @method remove
     * @param {Array} thisArray
     * @param {Function} func
     * @return {*}
     */
    ss.array.removeSome = function (thisArray, func) {
        var removed = [];
        for (var i = 0; i < thisArray.length;) {
            if (func(thisArray[i], i)) {
                removed.push(thisArray[i]);
                thisArray.splice(i, 1);
            }else {
                i++;
            }
        }

        return removed;
    };

    /**
     * 判断数组是否包含某个项
     * @method contains
     * @param {Array} thisArray
     * @param {*} item
     * @param {Number} [from] 从数组的某个索引开始判断，默认从第0个开始
     * @return {Boolean}
     */
    ss.array.contains = function (thisArray, item, from) {
        if (thisArray) {
            from = from || 0;
            for (var i = from; i < thisArray.length; i++) {
                if (thisArray[i] == item) {
                    return true;
                }
            }
        }
        return false;
    };

    /**
     * 将一个对象放到数组的某个索引中
     * @method add
     * @param {Array} array
     * @param {Object} item
     * @param {Number} [index]
     */
    ss.array.add = function (array, item, index) {
        if (ss.isDefined(index)) {
            array.splice(index, 0, item);
        } else {
            array.push(item);
        }
    };

    /**
     * 根据属性过滤,查找第一条数据
     * @method filterByProperty
     * @param {Array} array
     * @param {String} propertyName
     * @return {Array}
     */
    ss.array.findFirstIndexByProperty = function (array, propertyName, propertyValue) {
        if (array) {
            for (var i = 0; i < array.length; i++) {
                var v = array[i][propertyName];
                if (v == propertyValue) {
                    return i;
                }
            }
        }

        return -1;
    };

})();

(function () {

    var arraytree = window.arraytree = {};

    var ROOT_ID = -1;

    arraytree.calcTopNodes = function (array) {
        var children = arraytree.findChildrenNodes(array, ROOT_ID);
        console.log("topNodes,", children.length);
        return children.length;
    };

    arraytree.findChildrenNodes = function(array, id){
        var children = ss.array.filterByProperty(array, "parentid", id);
        return children;
    };

    arraytree.findSubTreeNodeIds = function(array, id){
        var tasks = [];
        tasks.push(id);

        var index = 0;
        var current = null;
        while (index < tasks.length) {
            current = tasks[index];
            ss.array.addAll(tasks, arraytree.findChildrenNodes(array, current).map(function (e) {
                return e.id;
            }));
            index++;
        }

        return tasks;
    };

    arraytree.deleteNode = function (array, id) {
        var tasks = arraytree.findSubTreeNodeIds(array, id);

        console.log("删除节点及其子节点", tasks);
        ss.array.removeSome(array, function (task) {
            return ss.array.contains(tasks, task.id);
        });
    };

    arraytree.findAndInsertTreeData = function (array, rowdata) {
        var index = ss.array.findFirstIndexByProperty(array, "id", rowdata.parentid);
        ss.array.add(array, rowdata, index + 1);
    };

    arraytree.addChildren = function (array, parentid, children) {
        var index = ss.array.findFirstIndexByProperty(array, "id", parentid);
        ss.array.addAll(array, children, index + 1);
    };

    arraytree.calcNodeVisible_ChildCount_Level = function (array) {

        var nodeMap = {};

        array.forEach(function (item) {
            var parent = nodeMap[item.parentid];

            if (item.tree_loaded) {
                item.childCount = 0;
            }

            if (parent) {
                item.tree_visible = parent.tree_visible && parent.tree_expanded;
                item.tree_level = parent.tree_level + 1;
                parent.childCount++;
            } else {
                item.tree_visible = true;
                item.tree_level = 0;
            }

            nodeMap[item.id] = item;
        });

        console.log("calcNodeVisible_ChildCount_Level, array=", array);
    };

    arraytree.findNodeIndex = function (array, id) {
        return ss.array.findFirstIndexByProperty(array, "id", id);
    };

    arraytree.findNode = function (array, id) {
        return ss.array.findFirstByProperty(array, "id", id);
    };

    arraytree.updateNode = function(array, data){
        var node = arraytree.findNode(array, data.id);
        ss.copyTo(data, node);
    }

})();

